home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / video / fly8111-.000 / fly8111- / fly8 / oplane.c < prev    next >
C/C++ Source or Header  |  1979-12-31  |  21KB  |  1,085 lines

  1. /* --------------------------------- oplane.c ------------------------------- */
  2.  
  3. /* This is part of the flight simulator 'fly8'.
  4.  * Author: Eyal Lebedinsky (eyal@ise.canberra.edu.au).
  5. */
  6.  
  7. /* Object description: shape and behaviour.
  8.  * Various planes (then see oclassic.c, obasic.c, oxplane.c).
  9. */
  10.  
  11. #include "plane.h"
  12.  
  13.  
  14. #define    RADAR_RANGE    10000
  15. #define    MINSHOOT    (2000L*VONE)
  16. #define    NOSHOOT        (200L*VONE)
  17. #define    PDAMAGE        10
  18.  
  19. static SHAPE shape_plane = {
  20.     0,
  21.     0,
  22.     SH_BEHIT,
  23.     10000*1000L,    /* weight */
  24.     0        /* drag */
  25. };
  26.  
  27. #define CCSIZE    8
  28. #define CCCOL    CCSIZE
  29. #define CCROW    (CCSIZE+1)
  30.  
  31. extern void FASTCALL FAR
  32. fDDshow (int frac, char *title, long value)
  33. {
  34.     static int    toprow = 4, row = 4, col = 12;
  35.     int        savefont;
  36.  
  37.     if (!title) {
  38.         if (frac >= 0)
  39.             toprow = row = frac;
  40.         if (value >= 0)
  41.             col = (int)value;
  42.         return;
  43.     }
  44.     if (row*CCROW >= CS->sizey) {
  45.         row = toprow;
  46.         col += 12;
  47.     }
  48.     savefont = font_set (0);
  49.     stroke_str  (col*CCCOL,     row*CCROW, title, CCSIZE, ST_HFG);
  50.     stroke_frac ((col+6)*CCCOL, row*CCROW, value, 0, frac, CCSIZE,
  51.         ST_HFG);
  52.     font_set (savefont);
  53.     ++row;
  54. }
  55.  
  56. extern void FASTCALL FAR
  57. fCCshow (int frac, char *title, long value)
  58. {
  59.     static int    toprow = 4, row = 4, col = 1;
  60.     int        savefont;
  61.  
  62.     if (!title) {
  63.         if (frac >= 0)
  64.             toprow = row = frac;
  65.         if (value >= 0)
  66.             col = (int)value;
  67.         return;
  68.     }
  69.     if (row*CCROW >= CS->sizey) {
  70.         row = toprow;
  71.         col += 12;
  72.     }
  73.     savefont = font_set (0);
  74.     stroke_str  (col*CCCOL,     row*CCROW, title, CCSIZE, ST_HFG);
  75.     stroke_frac ((col+6)*CCCOL, row*CCROW, value, 0, frac, CCSIZE,
  76.         ST_HFG);
  77.     font_set (savefont);
  78.     ++row;
  79. }
  80. #undef CCSIZE
  81. #undef CCCOL
  82. #undef CCROW
  83.  
  84. extern void FASTCALL FAR
  85. fCFshow (char *title, int value)
  86. {
  87.     fCCshow (3, title, value*1000L/FONE);
  88. }
  89.  
  90. extern void FASTCALL FAR
  91. fCAshow (char *title, int value)
  92. {
  93.     fCCshow (2, title, (long)ANG2DEG00 (value));
  94. }
  95.  
  96. extern void FASTCALL FAR
  97. fCVshow (char *title, int value)
  98. {
  99.     fCCshow (2, title, value*100L/VONE);
  100. }
  101.  
  102. extern void FAR
  103. CCnote (OBJECT *p, char *note)
  104. {
  105.     if (CC == p)
  106.         MsgPrintf (50, note);
  107. }
  108.  
  109. extern void FAR
  110. CCland (OBJECT *p)
  111. {
  112.     if (CC == p)
  113.         CCnote (p, "touchdown");
  114. }
  115.  
  116. extern void FAR
  117. CCfly (OBJECT *p)
  118. {
  119.     if (CC == p) {
  120.         CCnote (p, "takeoff");
  121.         EX->maxG = 10;
  122.     }
  123. }
  124.  
  125. /* We are off the ground. Did we land?
  126. */
  127. extern int FAR
  128. check_land (OBJECT *p)
  129. {
  130.     int    errs;
  131.  
  132.     if (p->R[Z] > EP->opt[5]*2)
  133.         return (0);
  134.     
  135.     EX->flags |= PF_ONGROUND;
  136.  
  137.     EX->misc[6] = p->R[Z]*VONE;
  138.  
  139.     errs = 0;
  140.  
  141.     if (p->R[Z] < 0L) {
  142.         CCnote (p, "under");
  143.         ++errs;
  144.     }
  145.  
  146.     if (!(EX->equip & EQ_GEAR)) {
  147.         CCnote (p, "belly");
  148.         ++errs;
  149.     }
  150.  
  151.     if (p->a[Y] > D90/4) {
  152.         CCnote (p, "chinese");
  153.         ++errs;
  154.     }
  155. #if 0
  156.     p->a[Y] = 0;
  157.     p->da[Y] = 0;
  158. #endif
  159. #if 0
  160.     if (p->a[X] < EP->gpitch-DEG(2)) {
  161.         CCnote (p, "nose down");
  162.         ++errs;
  163.     }
  164. #endif
  165.     if (EX->v[X] < -10*VONE || EX->v[X] > 10*VONE) {
  166.         CCnote (p, "sideways");
  167.         ++errs;
  168.     }
  169. #if 0
  170.     EX->v[X] = 0;
  171. #endif
  172. #if 0
  173.     if (p->V[Z] < -7*VONE) {
  174.         CCnote (p, "crash");
  175.         ++errs;
  176.     }
  177.     p->V[Z] = 0;
  178. #endif
  179.     if (!on_runway (p)) {
  180.         CCnote (p, "grass");
  181.         ++errs;
  182.     }
  183. #if 0
  184.     p->R[Z] = 0;
  185. #endif
  186.     if (!errs)
  187.         CCland (p);
  188.     return (errs);
  189. }
  190.  
  191. /* We are on the ground. Did we taking off?
  192. */
  193. extern int FAR
  194. check_takeoff (OBJECT *p)
  195. {
  196.     int    errs;
  197.  
  198.     errs = 0;
  199.     if (p->R[Z] < 0L) {
  200.         CCnote (p, "under");
  201.         ++errs;
  202.     }
  203.     if (!on_runway (p)) {
  204.         CCnote (p, "grass");
  205.         ++errs;
  206.     }
  207.     if (!(EX->equip & EQ_GEAR)) {
  208.         CCnote (p, "belly");
  209.         ++errs;
  210.     }
  211.     if (p->a[Y] > D90/4) {
  212.         CCnote (p, "chinese");
  213.         ++errs;
  214.     }
  215. #if 0
  216.     if (p->a[X] < EP->gpitch-DEG(2)) {
  217.         CCnote (p, "nose down");
  218.         ++errs;
  219.     }
  220. #endif
  221.     if (!errs && p->R[Z] > EP->opt[5]*2) {
  222.         EX->flags &= ~PF_ONGROUND;
  223.         CCfly (p);
  224.     }
  225.     return (errs);
  226. }
  227.  
  228. LOCAL_FUNC void FAR
  229. term_plane (BODY *b)
  230. {
  231.     parms_free ();
  232.     gen_term (b);
  233. }
  234.  
  235. extern void FAR
  236. supply (OBJECT *p, int mode)
  237. {
  238.     if (!mode) {
  239.         EX->fuel += TADJ(100)*100L;        /* 100lb/sec */
  240.         if (EX->fuel < EP->fuel_capacity*100L)
  241.             return;
  242.     }
  243.     EX->fuel = EX->parms->fuel_capacity*100L;    /* full tank */
  244.     memcpy (EX->stores, EX->parms->stores, sizeof (EX->stores));
  245.     p->damage = PDAMAGE;
  246. }
  247.  
  248. LOCAL_FUNC void NEAR
  249. btrail_delete (BTRAIL *h)
  250. {
  251.     BTRAIL    *hh;
  252.  
  253.     while (h) {
  254.         hh = h->next;
  255.         DEL (h);
  256.         h = hh;
  257.     }
  258. }
  259.  
  260. LOCAL_FUNC void NEAR
  261. free_plane (OBJECT *p)
  262. {
  263.     if (IS_PLANE(p)) {
  264.         if (EP)
  265.             (*flight_models[EP->opt[0]]) (p, 2);
  266.         DEL0 (EX->PIDthrottle);
  267.         DEL0 (EX->PIDpitch);
  268.         DEL0 (EX->PIDroll);
  269.         btrail_delete (EX->btrail);
  270.         DEL0 (EX);
  271.         p->e_type = 0;
  272.     }
  273. }
  274.  
  275. LOCAL_FUNC int FAR
  276. create_plane (OBJECT *p)
  277. {
  278.     E_PLANE    *e;
  279.     int    i;
  280.  
  281.     if (!NEW (e))
  282.         return (1);
  283.     p->e_type = ET_PLANE;
  284.     p->extra = e;
  285.  
  286.     if (F(NEW (e->PIDthrottle)) ||
  287.         F(NEW (e->PIDpitch)) ||
  288.         F(NEW (e->PIDroll))) {
  289.             free_plane (p);
  290.             return (1);
  291.     }
  292.  
  293.     e->parms = parms_get (st.options);
  294.     if (!e->parms) {
  295.             free_plane (p);
  296.         return (1);
  297.     }
  298.  
  299.     memcpy (e->PIDthrottle, &e->parms->PIDthrottle, sizeof (PID));
  300.     memcpy (e->PIDpitch,    &e->parms->PIDpitch,    sizeof (PID));
  301.     memcpy (e->PIDroll,     &e->parms->PIDroll,     sizeof (PID));
  302.  
  303.     e->flags |= PF_ONGROUND | PF_AUTOFLAP | PF_AUTOELEVATOR;
  304.  
  305.     e->hud |= HUD_ON;
  306.     e->hud1 |= e->parms->hudtype;
  307.  
  308.     supply (p, 1);
  309.     hud_setup (p);
  310.  
  311.     e->equip |= EQ_GEAR;
  312.     for (i = 0; i < rangeof(e->parms->gear) && e->parms->gear[i].z; ++i)
  313.         e->gear[i] = 100;
  314.     e->radar = 3*R_MODE;
  315.  
  316.     p->a[X] = e->parms->gpitch;
  317.     p->color = CC_WHITE;
  318.     p->time = FOREVER;
  319.     p->tom = p->tob + 5000;        /* 5 seconds grace */
  320.     p->damaging = 5;
  321.     p->flags |= F_VISIBLE | F_EXPORTED | F_MAINT | F_KEEPNAV;
  322.  
  323.     CP->eyez = e->parms->eyez;
  324.     CP->eyey = e->parms->eyey;
  325.     p->R[Z] = e->parms->opt[5];
  326.     e->maxG = 0;
  327.  
  328.     place_plane (p, 0);        /* default main runway */
  329.  
  330.     e->misc[6] = p->R[Z]*VONE;    /* hi-res height */
  331.  
  332.     (*flight_models[EP->opt[0]]) (p, 1);
  333.  
  334.     return (0);
  335. }
  336.  
  337. LOCAL_FUNC void FAR
  338. delete_plane (OBJECT *p)
  339. {
  340.     free_plane (p);
  341.     p->owner = 0;
  342.     p->ownerid = 0;
  343. }
  344.  
  345. extern void FAR
  346. dampen (short *old, int new, int factor)
  347. {
  348.     int    diff;
  349.  
  350.     factor = muldiv (factor, 67, st.interval);
  351.     if (factor < 1)
  352.         factor = 1;
  353.     diff = new - *old;
  354.     if (diff > factor || diff < -factor)
  355.         diff /= factor;
  356.     else if (diff > 0)
  357.         diff = 1;
  358.     else if (diff < 0)
  359.         diff = -1;
  360.     *old += diff;
  361. }
  362.  
  363. LOCAL_FUNC void NEAR
  364. ShootCue (OBJECT *p, OBJECT *target)
  365. {
  366.     VECT    R, RR;
  367.     ANGLE    perr, err;
  368.     int    t, limit, dist;
  369.     LVECT    IP;
  370.  
  371.     if (WE_MK82 == EX->weapon) {
  372.         BombSpeed (p, R);
  373.         BombIP (p->R, R, target->R[Z], IP);
  374.         if (est_dist (target->R, IP) < (Uint)SH(target)->extent)
  375.             EX->radar |= R_SHOOT;
  376.         return;
  377.     }
  378.  
  379.     SetKillCorrection (p, target, R, &t);
  380. #if 0
  381.     R[X] += TADJ (EX->tspeed[X]);
  382.     R[Y] += TADJ (EX->tspeed[Y]);
  383.     R[Z] += TADJ (EX->tspeed[Z]);
  384. #endif
  385.     R[X] = (int)((target->R[X] + R[X] - p->R[X])/VONE);
  386.     R[Y] = (int)((target->R[Y] + R[Y] - p->R[Y])/VONE);
  387.     R[Z] = (int)((target->R[Z] + R[Z] - p->R[Z])/VONE);
  388.     dist = ihypot3d (R);
  389.  
  390.     if (dist < MINSHOOT/VONE && dist > NOSHOOT/VONE) {
  391.         BulletSpeed (p, RR);
  392.         R[X] -= muldiv (RR[X], t, VONE*1000);
  393.         R[Y] -= muldiv (RR[Y], t, VONE*1000);
  394.         R[Z] -= muldiv (RR[Z], t, VONE*1000);
  395.         VxMmul (RR, R, p->T);
  396.         if (RR[Y] > 0) {
  397.             t = ihypot2d (RR[Z], RR[X]);
  398.             perr = ATAN (t, dist);
  399.             limit =  SH(target)->extent;
  400.             err = ATAN (limit/4, dist) + BULLETSCATTER/2;
  401.             if (perr < err)
  402.                 EX->radar |= R_SHOOT;
  403.         }
  404. #if 0
  405. DDshow (p, 4, 0, 25);
  406. DDshow (p, 0, "range", (long)dist);
  407. DDshow (p, 0, "miss", (long)t);
  408. DDshow (p, 2, "perr", (long)ANG2DEG00(perr));
  409. DDshow (p, 2, "err", (long)ANG2DEG00(err));
  410. #endif
  411.     }
  412. }
  413.  
  414. LOCAL_FUNC void NEAR
  415. do_radar (OBJECT *p)
  416. {
  417.     int    radar, dist, x, t, fref, shifty;
  418.     OBJECT    *pp, *target;
  419.     VECT    R, RR;
  420.     MAT    T;
  421.  
  422.     EX->radar &= ~R_SHOOT;
  423.     radar = EX->radar;
  424.  
  425.     if (!(radar & R_ON) || !EX->weapon) {
  426.         EX->target = 0;
  427.         return;
  428.     }
  429. /* target selection
  430. */
  431.  
  432. #define SEL3D    (D90/54)        /* 3.3 degrees wide circle */
  433. #define SEL5DX    (D90/34)        /* 5.3 degrees wide */
  434. #define SEL5DY    (D90/3*2)        /* 60 degrees high */
  435.  
  436.     if (T(target = EX->target) && target->id != EX->tid)
  437.         EX->target = target = 0;
  438.  
  439.     if (!target || !(radar & R_LOCK) ||    /* have target? */
  440.  
  441. /* Do not automatically release a locked target any more...
  442. */
  443.         ((EX->flags & (PF_AUTO|PF_CHASE)) &&
  444.             (target->flags & (F_HIT|F_STEALTH))) ||
  445.         est_dist (p->R, target->R) > RADAR_RANGE) {
  446.  
  447.         target = 0;            /* no, seek new one */
  448.         dist = RADAR_RANGE;
  449.  
  450.         if (radar & R_SELECT3) {
  451.             fref = SEL3D;
  452.             shifty = 0;
  453.         } else if (radar & R_SELECT20) {
  454.             fref = DEG2ANG (EX->hudarea);
  455.             shifty = fmul (EX->hudshift, fref);
  456.         } else if (radar & R_SELECT5) {
  457.             fref = -1;
  458.             shifty = fmul (EX->hudshift, DEG2ANG (EX->hudarea));
  459.         } else {
  460.             fref = 0;
  461.             shifty = 0;
  462.         }
  463.  
  464.         Mcopy (T, p->T);
  465.         Mxpose (T);
  466.         Mrotx (T, shifty);
  467.  
  468.         for (pp = CO; pp; pp = pp->next) {
  469.             if (!(pp->shflags & SH_BEHIT)
  470.                 || (pp->flags & (F_HIT|F_STEALTH))
  471.                 || ((radar & R_INTELCC) && !(pp->flags & F_CC))
  472.                 || pp == p
  473.                 || (p->flags & pp->flags & F_FRIEND))
  474.                 continue;
  475.             if (WE_MK82 == EX->weapon && pp->R[Z] != 0L)
  476.                 continue;
  477.             x = est_dist (p->R, pp->R);
  478.             if (fref && x < dist) {
  479.                 R[X] = (int)((pp->R[X]-p->R[X])/VONE);
  480.                 R[Y] = (int)((pp->R[Y]-p->R[Y])/VONE);
  481.                 R[Z] = (int)((pp->R[Z]-p->R[Z])/VONE);
  482.                 VMmul (RR, R, T);
  483.                 if (RR[Y] > 0) {
  484.                     if (fref < 0) {
  485.                         t = ATAN (RR[X], RR[Y]);
  486.                         if (iabs (t) > SEL5DX)
  487.                             continue;
  488.                         t = ATAN (RR[Z], RR[Y]);
  489.                         if (t < 0 || t > SEL5DY)
  490.                             continue;
  491.                     } else {
  492.                         t = ihypot2d (RR[X], RR[Z]);
  493.                         if (ATAN (t, RR[Y]) > fref)
  494.                             continue;
  495.                     }
  496.                 } else
  497.                     continue;
  498.             }
  499.             if (x < dist) {
  500.                 dist = x;
  501.                 target = pp;
  502.             }
  503.         }
  504.         if (!target) {                /* no new target */
  505.             EX->target = 0;
  506.             target = 0;
  507.             return;
  508.         }
  509.     }
  510.  
  511. /* target tracking data
  512. */
  513.     object_dynamics (target, st.interval);
  514.     if (EX->target != target) {            /* new target */
  515.         EX->target = target;
  516.         EX->tid = target->id;
  517.         Vcopy (EX->tspeed, target->V);
  518.         EX->taccel[X] = EX->taccel[Y] = EX->taccel[Z] = 0;
  519.         NEWTGT(p) = 11;        /* odd will show on first frame */
  520.  
  521.         if (EX->PIDthrottle) {
  522.             EX->PIDthrottle->I = 0L;
  523.             EX->PIDthrottle->Pprev = 0L;
  524.         }
  525.         if (EX->PIDpitch) {
  526.             EX->PIDpitch->I = 0L;
  527.             EX->PIDpitch->Pprev = 0L;
  528.         }
  529.         if (EX->PIDroll) {
  530.             EX->PIDroll->I = 0L;
  531.             EX->PIDroll->Pprev = 0L;
  532.         }
  533.  
  534.         if (st.quiet && p == CV)    /*fix 2*/
  535.             Snd->Effect (EFF_NOTICE, SND_ON);
  536.     } else {
  537.         EX->taccel[X] = target->V[X] - EX->tspeed[X];
  538.         EX->taccel[Y] = target->V[Y] - EX->tspeed[Y];
  539.         EX->taccel[Z] = target->V[Z] - EX->tspeed[Z];
  540.  
  541.         EX->tspeed[X] += muldiv (EX->taccel[X], st.interval, 1000);
  542.         EX->tspeed[Y] += muldiv (EX->taccel[Y], st.interval, 1000);
  543.         EX->tspeed[Z] += muldiv (EX->taccel[Z], st.interval, 1000);
  544.     }
  545.     ShootCue (p, target);
  546. }
  547.  
  548. extern void FAR
  549. eject (OBJECT *p)
  550. {
  551.     OBJECT    *obj;
  552.  
  553.     st.owner = p;
  554.     if (T(obj = create_object (O_CHUTE, 1))) {
  555.         p->gpflags &= ~GPF_PILOT;    /* indicate no one home */
  556.         p->flags |= F_MOD;
  557.         if (p == CC) {
  558.             obj->gpflags |= GPF_PILOT;    /* mark the chute */
  559.             p->flags |= F_HIT;        /* kill the plane */
  560.             MsgWPrintf (50, "ejected");
  561.         }
  562.         if (p == CV) {
  563.             save_viewport (CV);
  564.             CV = obj;
  565.             get_viewport (CV);
  566.         }
  567.     }
  568. }
  569.  
  570. /* Check if our object (assuming z=0) is inside the runway boundary.
  571. */
  572. extern int FAR
  573. on_runway (OBJECT *p)
  574. {
  575.     OBJECT    *w;
  576.     int    c, s;
  577.     long    lx, ly;
  578.  
  579.     for (w = CL; w; w = w->next) {
  580.         if (w->name != O_RUNWAY)
  581.             continue;
  582.         lx = p->R[X] - w->R[X];
  583.         ly = p->R[Y] - w->R[Y];
  584.         if (w->a[Z]) {
  585.             s = w->sinz;
  586.             c = w->cosz;
  587.             lx = (lx * c + ly * s)/FONE;
  588.             ly = (ly * c - lx * s)/FONE;
  589.         }
  590. #ifdef ACM_RUNWAY
  591. #define    W    (25L*VONE)
  592. #define    L    (2000L*VONE)
  593. #define    S    (0L*VONE)
  594.         if (labs(lx) < W) {
  595.             if (ly < L && ly > -S)
  596.                 return (1);
  597.         }
  598. #else
  599. #define    W    (64L*VONE)
  600. #define    L    (1750L*VONE)
  601. #define    S    (250L*VONE)
  602.         if (labs (lx) < W) {
  603.             if (ly < L && ly > -S)
  604.                 return (1);
  605.         } else if (labs (ly) < W) {
  606.             if (lx < L && lx > -S)
  607.                 return (1);
  608.         }
  609. #endif
  610. #undef    W
  611. #undef    L
  612. #undef    S
  613.     }
  614.     return (0);
  615. }
  616.  
  617. extern void FAR
  618. shoot (OBJECT *p, int weapon, int n, int seed, int interval)
  619. {
  620.     OBJECT    *w;
  621.     int    i, local, limited;
  622.  
  623.     st.owner = p;
  624.     Fsrand (seed);
  625.  
  626.     local = IS_PLANE(p);
  627.     limited = local && (EX->flags & PF_LIMITED);
  628.  
  629.         if (WE_MK82 == weapon) {
  630.         st.owner = p;
  631.         for (i = 0; i < n;  ++i) {
  632.             if (limited && EX->stores[WE_MK82-1] <= 0)
  633.                 break;
  634.             if (!(w = create_object (O_MK82, 1)))
  635.                 break;
  636.             if (local)
  637.                 --EX->stores[WE_MK82-1];
  638.             else
  639.                 ++p->misc[0];
  640.         }
  641.     } else if (WE_M61 == weapon) {
  642.         for (i = 0; i < n;  ++i) {
  643.             if (limited && EX->stores[WE_M61-1] <= 0)
  644.                 break;
  645.             if (!(w = create_object (O_M61, 1)))
  646.                 break;
  647.             if (local) {
  648.                 if (!(EX->stores[WE_M61-1]-- % 8))
  649.                     w->flags |= F_VISIBLE;
  650.             } else {
  651.                 if (!(p->misc[0]++ % 8))
  652.                     w->flags |= F_VISIBLE;
  653.             }
  654.         }
  655.     } else
  656.         i = 0;
  657.     if (i && (p->flags & F_EXPORTED))
  658.         remote_shoot (p, weapon, i, seed, interval);
  659. }
  660.  
  661. extern void FAR
  662. plane_smoke (OBJECT *p)
  663. {
  664.     int    i, t;
  665.     OBJECT    *s;
  666.  
  667.     if (p->damage >= PDAMAGE ||
  668.         !(st.flags1 & SF_SMOKE) ||
  669.         st.interval <= 0)
  670.         return;
  671.  
  672.     if (p->damage < PDAMAGE && (st.flags1 & SF_SMOKE)) {
  673.         for (i = 2*TADJ(PDAMAGE-p->damage); i-- > 0;)
  674.             if (T(s = create_object (O_SMOKE, 1))) {
  675.                 s->time = 3*TIMEPSEC;
  676.                 t = Frand () % st.interval;
  677.                 s->R[X] -= muldiv (p->V[X], t, 1000);
  678.                 s->R[Y] -= muldiv (p->V[Y], t, 1000);
  679.                 s->R[Z] -= muldiv (p->V[Z], t, 1000);
  680.             }
  681.     }
  682. }
  683.  
  684. extern int FAR
  685. dynamics_input (OBJECT *p)
  686. {
  687.     POINTER    *ptr;
  688.     int    i, t;
  689.     Ushort    temp;
  690.  
  691.     if (F(ptr = p->pointer) || !IS_PLANE(p))
  692.         return (1);
  693.  
  694.     if (p->flags & F_HIT) {
  695.         gen_dynamics (p, st.interval);
  696.         return (1);
  697.     }
  698.  
  699.     plane_smoke (p);
  700.  
  701.     if (!(p->gpflags & GPF_PILOT))
  702.         return (0);
  703. #if 0
  704.     if ((EX->flags & PF_AUTO) && !(EX->flags & PF_CHASE))
  705.         dynamics_auto (p);
  706.     else {
  707.         if ((*ptr->control->Read)(ptr, !(EX->flags & PF_CHASE))) {
  708.             MsgEPrintf (10, "pointer lost!");
  709.             Snd->Effect (EFF_NO_POINTER, SND_ON);
  710.             return (1);
  711.         }
  712.         dynamics_auto (p);
  713.     }
  714. #else
  715.     if ((*ptr->control->Read)(ptr, !(EX->flags & (PF_AUTO | PF_CHASE)))) {
  716.         MsgEPrintf (10, "pointer lost!");
  717.         Snd->Effect (EFF_NO_POINTER, SND_ON);
  718.         return (1);
  719.     }
  720.     dynamics_auto (p);
  721. #endif
  722.  
  723. /* pointer usage:
  724.  * a[0]    roll clockwise
  725.  * a[1]    pitch up
  726.  * a[2]    rudder right
  727.  * a[3]    throttle
  728.  * a[4]    trim pitch up
  729.  * a[5]    trim rudder right
  730.  * a[6]    flaps
  731.  * a[7]    spoilers
  732.  * a[8]    speed brakes
  733.  * a[9]    ground brakes
  734.  *
  735.  * b[0]  level
  736.  * b[1]  origin
  737.  * b[2]  fire
  738.  * b[3]  stable
  739.  * b[4]  reset roll
  740.  * b[5]  gear up/down
  741.  * b[6]  release radar lock
  742.  *
  743.  * opt[0] flight model
  744.  * opt[1] response
  745.  * opt[2]
  746.  * opt[3] turn speed (classic)
  747. */
  748.  
  749.     dampen (&EX->ailerons, ptr->l[0], EP->opt[1]);
  750.     dampen (&EX->elevators, ptr->l[1], EP->opt[1]);
  751.  
  752.     if (ptr->b[0]) {
  753.         p->a[X]  = 0;
  754.         p->a[Y]  = 0;
  755.         p->a[Z]  = 0;
  756.         p->da[X] = 0;
  757.         p->da[Y] = 0;
  758.         p->da[Z] = 0;
  759.         p->dae[X] = 0;
  760.         p->dae[Y] = 0;
  761.         p->dae[Z] = 0;
  762.         Mident (p->T);
  763.         (*ptr->control->Center)(ptr);
  764.     }
  765.  
  766.     if (ptr->b[1]) {
  767.         p->R[X] = 0;
  768.         p->R[Y] = 0;
  769.         p->R[Z] = 0;
  770.         ptr->l[3] = 0;
  771.     }
  772.  
  773.     if (ptr->b[2]) {
  774.         if (WE_MK82 == EX->weapon) {
  775.             if (EX->misc[11] + ptr->b[2] > 4)
  776.                 i = 4 - EX->misc[11];
  777.             else
  778.                 i = ptr->b[2];
  779.             if (i)
  780.                 shoot (p, WE_MK82, i, Frand(), st.interval);
  781.         } else if (WE_M61  == EX->weapon) {
  782.             shoot (p, WE_M61, 1+st.interval/(1000/(3000/60)),
  783.                 Frand(), st.interval);
  784.         }
  785.     }
  786.  
  787.     if (ptr->b[3])
  788.         (*ptr->control->Center)(ptr);
  789.  
  790.     if (ptr->b[4])
  791.         p->a[Y] = 0;
  792.  
  793.     if (ptr->b[5] > 0) {
  794.         if (EX->flags & PF_ONGROUND) {
  795.             MsgWPrintf (10, "Gear locked");
  796.         } else {
  797.             temp = EX->equip;
  798.             while (ptr->b[5] > 0) {
  799.                 SetOption (&EX->equip, EQ_GEAR);
  800.                 --ptr->b[5];
  801.             }
  802.             if ((temp ^ EX->equip) & EQ_GEAR) {
  803.                 if (CC == p) {
  804.                     MsgPrintf (50, "Gear %s",
  805.                         EX->equip&EQ_GEAR
  806.                         ? "lowered" : "raised");
  807.                     if (st.quiet)
  808.                         Snd->Effect (EFF_GEAR, SND_ON);
  809.                 }
  810.             }
  811.         }
  812.     }
  813.     if (EX->equip & EQ_GEAR) {        /* lower */
  814.         for (i = 0; i < rangeof(EP->gear) && EP->gear[i].ratedn; ++i) {
  815.             EX->gear[i] += TADJ (EP->gear[i].ratedn);
  816.             if (EX->gear[i] > 100)
  817.                 EX->gear[i] = 100;
  818.         }
  819.     } else {                /* raise */
  820.         for (i = 0; i < rangeof(EP->gear) && EP->gear[i].rateup; ++i) {
  821.             EX->gear[i] -= TADJ (EP->gear[i].rateup);
  822.             if (EX->gear[i] < 0)
  823.                 EX->gear[i] = 0;
  824.         }
  825.     }
  826.  
  827.     if (ptr->b[6])
  828.         EX->target = 0;
  829.  
  830.     EX->rudder = ptr->l[2];
  831.     if (ptr->l[3] > 75) {
  832.         EX->throttle = 100;
  833.         EX->afterburner = muldiv (ptr->l[3]-75, 100, 100-75);
  834.     } else {
  835.         EX->throttle = muldiv (ptr->l[3], 100, 75);
  836.         EX->afterburner = 0;
  837.     }
  838.     EX->tElevators = ptr->l[4];
  839.     EX->tRudder = ptr->l[5];
  840.     EX->flaps = ptr->l[6];
  841.     EX->spoilers = ptr->l[7];
  842.     EX->airbrake = ptr->l[8];
  843.     EX->brake = ptr->l[9];
  844.  
  845.     memset (ptr->b, 0, sizeof (ptr->b));    /* clear all buttons */
  846.  
  847.     if ((t = EX->tRudder+EX->rudder) > 100)
  848.         EX->rudder = 100 - EX->tRudder;
  849.     else if (t < -100)
  850.         EX->rudder = -100 - EX->tRudder;
  851.  
  852.     if ((t = EX->tElevators+EX->elevators) > 100)
  853.         EX->elevators = 100 - EX->tElevators;
  854.     else if (t < -100)
  855.         EX->elevators = -100 - EX->tElevators;
  856.  
  857.     return (0);
  858. }
  859.  
  860. LOCAL_FUNC void NEAR
  861. do_btrail (OBJECT *p)
  862. {
  863.     BTRAIL    *h;
  864.  
  865.     if (WE_M61 != EX->weapon || !(EX->hud2 & HUD_BTRAIL)) {
  866.         btrail_delete (EX->btrail);
  867.         EX->btrail = 0;
  868.         return;
  869.     }
  870.  
  871.     h = EX->btrail;
  872.     if (!h || h->ms >= 1000/25) {        /* limit frequency */
  873.         if (!NEW (h))
  874.             return;
  875.         BulletSpeed (p, h->V);
  876.         LVcopy (h->R, p->R);
  877.         h->ms = 0;
  878.         h->next = EX->btrail;
  879.         EX->btrail = h;
  880.     }
  881.     for (; h; h = h->next) {
  882.         h->ms += st.interval;
  883.         h->V[Z] -= TADJ (GACC);
  884.         h->R[X] += TADJ (h->V[X]);
  885.         h->R[Y] += TADJ (h->V[Y]);
  886.         h->R[Z] += TADJ (h->V[Z]);
  887.         if (h->ms > 1500) {
  888.             btrail_delete (h->next);
  889.             h->next = 0;
  890.             break;
  891.         }
  892.     }
  893. }
  894.  
  895. /* arm the lapms panel.
  896. */
  897. LOCAL_FUNC void NEAR
  898. do_lamps (OBJECT *p)
  899. {
  900.     long    t;
  901.     int    i;
  902.  
  903.     if (IS_PLANE(p) && (p->gpflags & GPF_PILOT)) {
  904.         LAMP_SET_OFF (LAMP_GLIMIT);
  905.         LAMP_SET_OFF (LAMP_STALL);
  906.         LAMP_SET_OFF (LAMP_FUEL);
  907.         LAMP_SET_OFF (LAMP_ALT);
  908.         LAMP_SET_OFF (LAMP_PULLUP);
  909.         LAMP_SET_OFF (LAMP_EJECT);
  910.         LAMP_SET_OFF (LAMP_DAMAGE);
  911.         LAMP_SET_OFF (LAMP_EJECT);
  912.         LAMP_SET_OFF (LAMP_DAMAGE);
  913.         LAMP_SET_OFF (LAMP_GEAR);
  914.  
  915.         if (EX->flags & PF_GLIMIT)
  916.             LAMP_SET_RED (LAMP_GLIMIT, LAMP_ON);
  917.  
  918.         if (EX->flags & PF_STALL)
  919.             LAMP_SET_RED (LAMP_STALL, LAMP_ON);
  920.  
  921.         if (EX->fuel <= 0)
  922.             LAMP_SET_RED (LAMP_FUEL, LAMP_ON|LAMP_BLINK);
  923.         else {
  924.             t = 1000L * EX->fuel / EP->fuel_capacity;
  925.             if (t < 10000L)
  926.                 LAMP_SET_RED (LAMP_FUEL, LAMP_ON);
  927.         }
  928.  
  929.         if (!(EX->flags & PF_ONGROUND) && !(EX->equip & EQ_GEAR)) {
  930.             if ((int)EX->misc[17] < FONE) {
  931.                 LAMP_SET_RED (LAMP_ALT, LAMP_ON);
  932.                 if ((int)EX->misc[17] < FCON(0.2))
  933.                     LAMP_SET_RED (LAMP_PULLUP,
  934.                             LAMP_ON|LAMP_BLINK);
  935.             }
  936.         }
  937.  
  938.         if (p->damage <= 0)
  939.             LAMP_SET_RED (LAMP_EJECT, LAMP_ON|LAMP_BLINK);
  940.         else if (p->damage <= 3)
  941.             LAMP_SET_RED (LAMP_DAMAGE, LAMP_ON);
  942.  
  943.         for (i = 0; i < rangeof (EP->gear) && EP->gear[i].z; ++i) {
  944.             if (EX->gear[i] > 0 && EX->gear[i] < 100) {
  945.                 LAMP_SET_GREEN (LAMP_GEAR, LAMP_ON|LAMP_BLINK);
  946.                 break;
  947.             }
  948.         }
  949.  
  950. #define GEARVLIMIT    (150*VONE)
  951.         if (EX->equip & EQ_GEAR) {
  952.             if (p->speed > GEARVLIMIT)
  953.                 LAMP_SET_RED (LAMP_GEAR, LAMP_ON|LAMP_BLINK);
  954.             else
  955.                 LAMP_SET_GREEN (LAMP_GEAR, LAMP_ON);
  956.         }
  957. #undef GEARVLIMIT
  958.     }
  959. }
  960.  
  961. LOCAL_FUNC void FAR
  962. dynamics_plane (OBJECT *p, int interval)
  963. {
  964. CCshow (p, 2, 0,  1);
  965. DDshow (p, 2, 0, 15);
  966.     if (MODEL_CLASSIC != EP->opt[0]) {
  967.         int    intsave;
  968.  
  969.         intsave = st.interval;
  970.         st.interval = st.misc[6];
  971.         if (EX->flags & PF_ONGROUND)
  972.             st.interval /= 4;
  973.         if (st.interval < 1)
  974.             st.interval = 1;
  975.         for (; interval > st.interval; interval -= st.interval) {
  976.             (*flight_models[EP->opt[0]]) (p, 0);
  977.             object_update (p, st.interval);
  978.         }
  979.         st.interval = interval;
  980.         (*flight_models[EP->opt[0]]) (p, 0);
  981.         object_update (p, st.interval);
  982.         st.interval = interval = intsave;
  983.     } else {
  984.         (*flight_models[EP->opt[0]]) (p, 0);
  985.         object_update (p, interval);
  986.     }
  987.     do_radar (p);
  988.     do_btrail (p);
  989.     do_lamps (p);
  990.     sys_poll (8);        /* give the timer a chance */
  991. }
  992.  
  993. LOCAL_FUNC void FAR
  994. hit_plane (OBJECT *p, int speed, int extent, int damaging)
  995. {
  996.     if (p->damage <= 0 && !(p->flags & F_HIT)) {
  997.         p->color = ST_FIRE1;
  998.         p->flags |= F_HIT|F_MOD;
  999.         p->shflags |= SH_G;
  1000.         p->time = FOREVER;
  1001.         if (p == CC && !(EX->hud1&HUD_VALARM))
  1002.             MsgEPrintf (50, "YOU'RE HIT, EJECT!");
  1003.         if (p->damage == 0 && !(p->flags & F_IMPORTED) &&
  1004.             !(p->flags&F_CC))
  1005.             eject (p);
  1006.     }
  1007.  
  1008. /* explode.
  1009. */
  1010.     st.owner = p;
  1011.     if (p->damage >= -20)        /* limit vicious loops */
  1012.         object_break (Frand()%5 + 2, speed, extent, 0);
  1013.     object_rand (p, speed, extent, 1);
  1014. }
  1015.  
  1016. extern void FAR
  1017. place_plane (OBJECT *p, short home)
  1018. {
  1019.     p->home = home;
  1020.  
  1021.     p->R[X] = ils[home].R[X];
  1022.     p->R[Y] = ils[home].R[Y];
  1023.     p->R[Z] += ils[home].R[Z];
  1024.     p->longitude = ils[home].longitude;
  1025.     p->latitude  = ils[home].latitude;
  1026.     p->a[Z] = -ils[home].localizer;
  1027.     Mobj (p);
  1028. }
  1029.  
  1030. extern void FAR
  1031. emit_drone (void)
  1032. {
  1033.     OBJECT    *p;
  1034.     POINTER *ptr;
  1035.  
  1036.     if (F(ptr = pointer_select ("random")))
  1037.         return;
  1038.     st.options = st.dtype ? st.dtype : st.ptype;
  1039.     if (!(p = create_object (O_PLANE, 1)))
  1040.         return;
  1041.     p->pointer = ptr;
  1042.     p->gpflags |= GPF_PILOT;
  1043.     EX->flags |= PF_AUTO;
  1044.  
  1045.     place_plane (p, nav_find (""));
  1046.  
  1047.     LIFETIME(p) = 5*1000;    /* let it take off nicely */
  1048.     SPEED(p) = 250;
  1049.     HEADING(p)  = p->a[Z];
  1050.     ALTITUDE(p) = (int)(p->R[Z]/VONE) + 100;
  1051. }
  1052.  
  1053. extern char * FAR
  1054. get_wname (int w)
  1055. {
  1056.     switch (w) {
  1057.     case WE_M61:
  1058.         return ("GUN");
  1059.     case WE_MK82:
  1060.         return ("MK82");
  1061.     default:
  1062.         return ("XXX");
  1063.     }
  1064. }
  1065.  
  1066. BODY FAR BoPlane = {
  1067.     0,
  1068.     0,
  1069.     "PLANE",
  1070.     &shape_plane,
  1071.     gen_read,
  1072.     term_plane,
  1073.     create_plane,
  1074.     delete_plane,
  1075.     dynamics_plane,
  1076.     hit_plane
  1077. };
  1078.  
  1079. #undef RADAR_RANGE
  1080. #undef MINSHOOT
  1081. #undef PDAMAGE
  1082. #undef SEL3D
  1083. #undef SEL5DX
  1084. #undef SEL5DY
  1085.